React - state en levenscyclus
React-componenten hebben een ingebouwd state object. Daarin worden eigenschapswaarden opgeslagen die bij de component horen. Wanneer het state object gewijzigd wordt, wordt de component opnieuw weergegeven (re-rendered).
Ouder- of kindcomponenten kunnen weten niet of een bepaald component stateful of stateless is. Zij weten ook niet of een component wordt gedefinieerd als een functie of een klasse.
Het state object is dus lokaal of ingekapseld in de klasse waartoe het behoort en het is niet toegankelijk voor andere componenten.
Doelstelling
Het state object heeft twee doelstellingen die met elkaar nauw verbonden zijn. Het dient om gegevens over de component bij te houden en dient als trigger om de component opnieuw weer te geven (re-rendering).
Als voorbeeld gaan we een like-knop aan de Marvel-component toevoegen. Maar wel op die manier dat we de like-knop ook in een andere app kunnen gebruiken. We gaan er dus een op zichzelf staande component van maken, opmaak incluis.
Stappen
- De code voor de
LikeButtonknop plaatsen we in een bestand met de naam UIControls.js. - We maken een klassencomponent die een knop weergeeft:
class LikeButton extends React.Component { render() { return <button>{typeof this.props.caption !== 'undefined' ? this.props.caption : 'button'}</button> } } - En we testen die control in ui-controls.html pagina:
<!DOCTYPE html> <html lang="nl"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Snel starten met React</title> <!-- Note: when deploying, replace "development.js" with "production.min.js". --> <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> <script type="text/babel" src="js/UIControls.js"></script> </head> <body> <div id="root"> <div id="one"></div> <div id="two"></div> </div> <script type="text/babel"> ReactDOM.render( <div> <LikeButton caption="Mijn knop" /> <LikeButton /> </div>, document.querySelector('#two')) </script> </body> </body> </html>- We laden het js/UIControls.js bestand en geven me dat het van het type
text/babelis. - In de render methode van ReactDOM roepen we de LikeButton klasse met de
<LikeButton/>XML notatie van JSX. - We maken gebruik van wat geleerd hebben over
propsen geven aan de<LikeButton/>XML tag hetcaptionattribuut mee. Dat wordt door JSX omgezet in eenpropsobject van deLikeButtonklasse. De tweede knop heeft geencaptionattribuut en deLikeButtonklasse toont dan ook de standaard tekst. - Met dit als resultaat:
react-bare-button-class - We voegen wat CSS toe aan de component zelf:
class LikeButton extends React.Component { buttonStyle = { boxShadow: "inset 0px 1px 0px 0px #97c4fe", background: "linear-gradient(to bottom, #3d94f6 5%, #1e62d0 100%)", backgroundColor: "#3d94f6", borderRadius: "6px", border: "1px solid #337fed", display: "inline-block", cursor: "pointer", color: "#ffffff", fontFamily: "Arial", fontSize: "15px", fontWeight: "bold", padding: "6px 24px", textShadow: "0px 1px 0px #1570cd" } render() { return <button style={this.buttonStyle}>{typeof this.props.caption !== 'undefined' ? this.props.caption : 'button'}</button> } } - En dat ziet er al veel beter uit:
react-button-with-style-class
- We laden het js/UIControls.js bestand en geven me dat het van het type
- Vermits we een like knop willen maken moet de knop bijhouden hoeveel keren erop geklikt werd. Daarvoor gaan we het ingebouwde
stateobject van React klassencomponenten gebruiken. We declareren het aantal likes in de constructor als een eigenschap van hetstateobject met de naamlikes:constructor(props) { super(props); this.state = { likes: 0 }; } - We voegen een incrementLike klikafhandelaar methode aan de klassencomponent toe die het aantal likes met 1 verhoogt telkens wanneer op de knop wordt geklikt:
incrementLike = () => { let newCount = this.state.likes + 1; this.setState({ likes: newCount }); }; - We passen de return in de
rendermethode aan:- het aantal likes tonen we in een
labelen we stijlen het:labelStyle = { display: "inline-block", color: "#ffffff", backgroundColor: "#3d94f6", textShadow: "0px 1px 0px #1570cd", padding: "6px 24px", textShadow: "0px 1px 0px #1570cd", borderRadius: "6px", border: "1px solid #337fed" } - de
buttonen hetlabelzetten we in eendiv
render() { return <div><button onClick={this.incrementLike} style={this.buttonStyle}>{typeof this.props.caption !== 'undefined' ? this.props.caption : 'button'}</button> <label style={this.labelStyle}>{this.state.likes}</label> </div> - het aantal likes tonen we in een
- En we testen die control in ui-controls.html pagina:
<!DOCTYPE html> <html lang="nl"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Snel starten met React</title> <!-- Note: when deploying, replace "development.js" with "production.min.js". --> <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> <script type="text/babel" src="js/UIControls.js"></script> </head> <body> <div id="root"> <div id="one"></div> <div id="two"></div> </div> <script type="text/babel"> ReactDOM.render( <div> <LikeButton caption="I like"/> <LikeButton caption="I like"/> </div>, document.querySelector('#two')) </script> </body> </html> - Met dit als resultaat:
react-like-button-class